#!/usr/bin/env python
# coding: utf-8

# In[34]:


"""Spectral谱聚类"""

import numpy as np
import pandas as pd #用于读取csv文件
from sklearn.cluster import KMeans
import math
import matplotlib.pyplot as plt

# 读取数据，存储为矩阵格式
M=np.array(pd.read_csv('D:/课程/jiqixuexi/dataset_circles.csv')) 
# 包含x、y、类别的矩阵
M1 = np.delete(M, -1, axis=1) 
# 去除类别列，成为散点坐标集合的矩阵形式


# 谱聚类算法

#欧式距离计算
def distance(v1, v2):
    # v1、v2为两个向量
    d = np.sum(np.square(v1-v2))
    return d

# 获得距离矩阵
def dist_matrix(M):
    n = len(M)  #样本数量
    dist_matrix = np.zeros((n, n)) # 初始化距离矩阵为n×n的全0矩阵
    for i in range(n):
        for j in range(i+1, n):
            dist_matrix[i][j] = dist_matrix[j][i] = distance(M[i], M[j])
    return dist_matrix

# 获得邻接矩阵W
def W1(data, k):
    # data为数据集合，k为KMeans参数
    n = len(data) #样本数量
    dM = dist_matrix(data)
    W = np.zeros((n, n)) # 初始化邻接矩阵为n×n的全0矩阵
    for idx, item in enumerate(dM):
        idx_array = np.argsort(item)  # 每一行距离列表进行排序,得到对应的索引列表
        W[idx][idx_array[1:k+1]] = 1
    transpW =np.transpose(W)
    return (W+transpW)/2

# 获得度（权值）矩阵D
def D1(W):
    D = np.diag(sum(W))
    return D

# 获得拉普拉斯矩阵
def L1(D,W):
    L = D-W
    return L

# 获得拉普拉斯矩阵的特征矩阵E
def E1(L, n_cluster):
    # L为拉氏矩阵，n_cluster为聚类数目
    eigval, eigvec = np.linalg.eig(L)
    ix = np.argsort(eigval)[0:n_cluster]
    return eigvec[:, ix]

# 谱聚类
def Spectralcluster(data, n_cluster, k):
    data = np.array(data)
    # 获得各类矩阵
    W = W1(data, k) 
    D = D1(W)
    L = L1(D,W) 
    # 获得拉氏特征值
    eigvec = E1(L, n_cluster)
    clf = KMeans(n_clusters=n_cluster)
    # 前述已讲过KMeans算法，直接调用sklearn库中的KMeans聚类算法
    s = clf.fit(eigvec)  # 聚类
    label = s.labels_
    return  label


# 二维空间显示聚类结果
def Spectralshow(data, clusterResult, n_cluster):
    # clusterResult为聚类结果，n_cluster为聚类个数
    n = len(data)
    scatterColors = ['black', 'blue', 'green', 'yellow', 'red', 'purple', 'orange']
    for i in range(n_cluster):
        color = scatterColors[i % len(scatterColors)]
        x1= []; y1=[]
        for j in range(n):
            if clusterResult[j] == i:
                x1.append(data[j,0])
                y1.append(data[j, 1])
        plt.scatter(x1, y1, c=color, marker='o')
    plt.xlabel('feature 1')
    plt.ylabel('feature 2')
    plt.title('Spectral cluster result')  # 标题
    plt.show()


# 进行谱聚类

n_cluster = 2 # 定义聚类数目和 k值
knn_k = 5

# 读取数据，存储为矩阵格式
M=np.array(pd.read_csv('D:/课程/jiqixuexi/dataset_circles.csv')) 
# 包含x、y、类别的矩阵
M1 = np.delete(M, -1, axis=1) 
# 去除类别列，成为散点坐标集合的矩阵形式

label = Spectralcluster(M1, cluster_num, knn_k)# 进行谱聚类
Spectralshow(M1, label, n_cluster)# 进行二维图像显示


# In[ ]:




